local extension=Package("ecyhelp",Package.SpecialPack)
extension.extensionName="aa__erciyuan"
extension.game_modes_whitelist={"kuanglang_mode"}
Fk:loadTranslationTable{
  ["aa__erciyuan"] = "二次元辅助",
  ["ecyhelp"] = "二次元辅助",
}

--[[
for _, pkname in ipairs(Fk.package_names) do
  local pack = Fk.packages[pkname]

  for _, skel in ipairs(pack.card_skels) do
    local card = skel:createCardPrototype()
    if card then
      card.package = extension
      Fk.skills[card.skill.name] = Fk.skills[card.skill.name] or card.skill
      Fk.all_card_types[card.name] = card
      table.insert(Fk.all_card_names, card.name)
    end
  end
  for _, tab in ipairs(pack.card_specs) do
    extension:addCard(Fk:cloneCard(tab[1], tab[2], tab[3]))
  end

end

Fk:addCards(extension.cards)
--]]
--- 根据id返回相应的卡牌。
---@param id integer @ 牌的id
---@param ignoreFilter? boolean @ 是否要无视掉锁定视为技，直接获得真牌
---@return Card @ 这个id对应的卡牌
function Fk:getCardById(id, ignoreFilter)
  if id == nil then return nil end
  if type(id) ~= "number" then--兼容实体牌
    if id.id then
      return id
    end
  end
  local card_tab = (id >= -1) and self.cards or self.printed_cards
  local ret = card_tab[id]
  if not ignoreFilter then
    ret = self.filtered_cards[id] or card_tab[id]
  end
  return ret
end


---@class SkillSpec
---@field public name string @ 技能名
---@field public frequency? Frequency @ 技能发动的频繁程度，通常compulsory（锁定技）及limited（限定技）用的多。
---@field public mute? boolean @ 决定是否关闭技能配音
---@field public no_indicate? boolean @ 决定是否关闭技能指示线
---@field public anim_type? string|AnimationType @ 技能类型定义
---@field public global? boolean @ 决定是否是全局技能
---@field public attached_equip? string @ 属于什么装备的技能？
---@field public switch_skill_name? string @ 转换技名字
---@field public relate_to_place? string @ 主将技/副将技
---@field public on_acquire? fun(self: UsableSkill, player: ServerPlayer, is_start: boolean)
---@field public on_lose? fun(self: UsableSkill, player: ServerPlayer, is_death: boolean)
---@field public dynamic_desc? fun(self: UsableSkill, player: Player, lang: string): string
---@field public attached_skill_name? string @ 给其他角色添加技能的名称

---@class UsableSkillSpec: SkillSpec
---@field public main_skill? UsableSkill
---@field public max_use_time? integer[]
---@field public expand_pile? string | integer[] | fun(self: UsableSkill, player: ServerPlayer): integer[]|string? @ 额外牌堆，牌堆名称或卡牌id表
---@field public derived_piles? string | string[]
---@field public max_phase_use_time? integer
---@field public max_turn_use_time? integer
---@field public max_round_use_time? integer
---@field public max_game_use_time? integer
---@field public times? integer | fun(self: UsableSkill): integer
---@field public min_target_num? integer
---@field public max_target_num? integer
---@field public target_num? integer
---@field public target_num_table? integer[]
---@field public min_card_num? integer
---@field public max_card_num? integer
---@field public card_num? integer
---@field public card_num_table? integer[]

---@class StatusSkillSpec: SkillSpec

---@alias TrigFunc fun(self: TriggerSkill, event: Event, target: ServerPlayer, player: ServerPlayer, data: any): any
---@class TriggerSkillSpec: UsableSkillSpec
---@field public global? boolean
---@field public events? Event | Event[]
---@field public refresh_events? Event | Event[]
---@field public priority? number | table<Event, number>
---@field public on_trigger? TrigFunc
---@field public can_trigger? TrigFunc
---@field public on_cost? TrigFunc
---@field public on_use? TrigFunc
---@field public on_refresh? TrigFunc
---@field public can_refresh? TrigFunc
---@field public can_wake? TrigFunc


---老函数
---试着给老方法写一个兼容
---目前思路是把老方法写的技能当做骨骼，然后根据实际做不同的effect，但是不是太麻烦了
---@param spec TriggerSkillSpec
---@return TriggerSkill
function fk.CreateTriggerSkill(spec)
  assert(type(spec.name) == "string")
  --assert(type(spec.on_trigger) == "function")
      -- 1. 构造骨骼名
  --local skel_name = spec.name or ("trig_" .. tostring(event))
  local skel_name = spec.name
      -- 2. 构造骨骼

  local newspec={
        name = skel_name,
  }
  if spec.frequency then assert(type(spec.frequency) == "string") end

  local frequency = spec.frequency or Skill.NotFrequent
  newspec.tags={frequency}
  newspec.dynamicName = spec.dynamic_name
  newspec.dynamicDesc = spec.dynamic_desc
  local skeleton = fk.CreateSkill(newspec)
  --fk.readUsableSpecToSkill(skill, spec)
  fk.readCommonSpecToSkill(skeleton, spec)

  if type(spec.events) == "table" then
    local sk ={}
    if spec.can_trigger then
        sk.can_trigger = spec.can_trigger
    end
    if spec.can_wake then
        sk.can_Wake = spec.can_wake
    end
    if spec.on_trigger then sk.on_trigger = spec.on_trigger end
    if spec.on_cost then sk.on_cost = spec.on_cost end
    if spec.on_use then sk.on_use = spec.on_use end
    if not spec.cost and spec.frequency == Skill.Compulsory then
      sk.on_cost = function(self, event, target, player, data)
        return true
      end
    end
    if spec.trigger_times then sk.trigger_times  = spec.trigger_times end
    sk.priority = spec.priority or 1
    sk.mute = spec.mute 
    sk.no_indicate = spec.no_indicate
    sk.anim_type = spec.anim_type
    for _, event in ipairs(spec.events) do
     skeleton:addEffect(event,sk)
    end
  end

  if type(spec.refresh_events) == "table" then
    local sk ={}
    if spec.can_refresh then sk.can_refresh = spec.can_refresh end
    if spec.on_refresh then sk.on_refresh = spec.on_refresh end
    for _, event in ipairs(spec.refresh_events) do
      skeleton:addEffect(event,sk)
    end
  end

  Fk.skill_skels[skeleton.name] = skel
  local skill = skeleton:createSkill()



  --[[
  if type(spec.global) == "boolean" then skill.global = spec.global end

  if spec.on_trigger then skill.trigger = spec.on_trigger end

  if spec.can_trigger then
    if spec.frequency == Skill.Wake then
      skill.triggerable = function(self, event, target, player, data)
        return spec.can_trigger(self, event, target, player, data) and
          skill:enableToWake(event, target, player, data)
      end
    else
      skill.triggerable = spec.can_trigger
    end
  end

  if skill.frequency == Skill.Wake and spec.can_wake then
    skill.canWake = spec.can_wake
  end

  if spec.on_cost then skill.cost = spec.on_cost end
  if spec.on_use then skill.use = spec.on_use end

  if spec.can_refresh then
    skill.canRefresh = spec.can_refresh
  end

  if spec.on_refresh then
    skill.refresh = spec.on_refresh
  end

  if spec.attached_equip then
    if not spec.priority then
      spec.priority = 0.1
    end
  elseif not spec.priority then
    spec.priority = 1
  end
  --]]


  return skill
end

---@class ActiveSkillSpec: UsableSkillSpec
---@field public can_use? fun(self: ActiveSkill, player: Player, card?: Card, extra_data: any): any @ 判断主动技能否发动
---@field public card_filter? fun(self: ActiveSkill, to_select: integer, selected: integer[], player: Player): any @ 判断卡牌能否选择
---@field public target_filter? fun(self: ActiveSkill, to_select: integer, selected: integer[], selected_cards: integer[], card?: Card, extra_data: any, player: Player?): any @ 判定目标能否选择
---@field public feasible? fun(self: ActiveSkill, selected: integer[], selected_cards: integer[], player: Player): any @ 判断卡牌和目标是否符合技能限制
---@field public on_use? fun(self: ActiveSkill, room: Room, cardUseEvent: CardUseStruct | SkillEffectEvent): any
---@field public on_action? fun(self: ActiveSkill, room: Room, cardUseEvent: CardUseStruct | SkillEffectEvent, finished: boolean): any
---@field public about_to_effect? fun(self: ActiveSkill, room: Room, cardEffectEvent: CardEffectEvent | SkillEffectEvent): any
---@field public on_effect? fun(self: ActiveSkill, room: Room, cardEffectEvent: CardEffectEvent | SkillEffectEvent): any
---@field public on_nullified? fun(self: ActiveSkill, room: Room, cardEffectEvent: CardEffectEvent | SkillEffectEvent): any
---@field public mod_target_filter? fun(self: ActiveSkill, to_select: integer, selected: integer[], player: Player, card?: Card, distance_limited: boolean, extra_data: any): any
---@field public prompt? string|fun(self: ActiveSkill, selected_cards: integer[], selected_targets: integer[]): string @ 提示信息
---@field public interaction? fun(self: ActiveSkill, player: Player): any
---@field public target_tip? fun(self: ActiveSkill, to_select: integer, selected: integer[], selected_cards: integer[], card?: Card, selectable: boolean, extra_data: any): string|TargetTipDataSpec?
---@field public handly_pile? boolean @ 是否能够选择"如手牌使用或打出"的牌
---@field public fix_targets? fun(self: ActiveSkill, player: Player, card?: Card, extra_data: any): any @ 设置固定目标

---@param spec ActiveSkillSpec
---@return ActiveSkill
function fk.CreateActiveSkill(spec)
  local skel_name = spec.name
  -- 2. 构造骨骼

  local newspec={
    name = skel_name,
  }
  if spec.frequency then assert(type(spec.frequency) == "string") end

  local frequency = spec.frequency or Skill.NotFrequent
  newspec.tags={frequency}
  newspec.dynamicName = spec.dynamic_name
  newspec.dynamicDesc = spec.dynamic_desc
  local skeleton = fk.CreateSkill(newspec)
  --fk.readUsableSpecToSkill(skill, spec)
  fk.readCommonSpecToSkill(skeleton, spec)
  skeleton:addEffect("active",spec)
  Fk.skill_skels[skeleton.name] = skel
  local skill = skeleton:createSkill()
  return skill
end

---@class ViewAsSkillSpec: UsableSkillSpec
---@field public card_filter? fun(self: ViewAsSkill, to_select: integer, selected: integer[], player: Player): any @ 判断卡牌能否选择
---@field public view_as fun(self: ViewAsSkill, cards: integer[], player: Player): Card? @ 判断转化为什么牌
---@field public pattern? string
---@field public enabled_at_play? fun(self: ViewAsSkill, player: Player): any
---@field public enabled_at_response? fun(self: ViewAsSkill, player: Player, response: boolean): any
---@field public before_use? fun(self: ViewAsSkill, player: ServerPlayer, use: CardUseStruct): string?
---@field public after_use? fun(self: ViewAsSkill, player: ServerPlayer, use: CardUseStruct): string? @ 使用此牌后执行的内容，注意打出不会执行
---@field public prompt? string|fun(self: ActiveSkill, selected_cards: integer[], selected: integer[]): string
---@field public interaction? fun(self: ActiveSkill, player: Player): any
---@field public handly_pile? boolean @ 是否能够选择"如手牌使用或打出"的牌

---@param spec ViewAsSkillSpec
---@return ViewAsSkill
function fk.CreateViewAsSkill(spec)
  local skel_name = spec.name
  -- 2. 构造骨骼

  local newspec={
    name = skel_name,
  }
  if spec.frequency then assert(type(spec.frequency) == "string") end

  local frequency = spec.frequency or Skill.NotFrequent
  newspec.tags={frequency}
  newspec.dynamicName = spec.dynamic_name
  newspec.dynamicDesc = spec.dynamic_desc
  local skeleton = fk.CreateSkill(newspec)
  --fk.readUsableSpecToSkill(skill, spec)
  fk.readCommonSpecToSkill(skeleton, spec)
  skeleton:addEffect("viewas",spec)
  local skill = skeleton:createSkill()
  Fk.skill_skels[skeleton.name] = skel
  return skill
end

---@class DistanceSpec: StatusSkillSpec
---@field public correct_func? fun(self: DistanceSkill, from: Player, to: Player): integer?
---@field public fixed_func? fun(self: DistanceSkill, from: Player, to: Player): integer?

---@param spec DistanceSpec
---@return DistanceSkill
function fk.CreateDistanceSkill(spec)
  local skel_name = spec.name
  -- 2. 构造骨骼

  local newspec={
    name = skel_name,
  }
  if spec.frequency then assert(type(spec.frequency) == "string") end

  local frequency = spec.frequency or Skill.NotFrequent
  newspec.tags={frequency}
  newspec.dynamicName = spec.dynamic_name
  newspec.dynamicDesc = spec.dynamic_desc
  local skeleton = fk.CreateSkill(newspec)
  --fk.readUsableSpecToSkill(skill, spec)
  fk.readCommonSpecToSkill(skeleton, spec)
  skeleton:addEffect("distance",spec)
  local skill = skeleton:createSkill()
  Fk.skill_skels[skeleton.name] = skel
  return skill
end

---@class ProhibitSpec: StatusSkillSpec
---@field public is_prohibited? fun(self: ProhibitSkill, from: Player, to: Player, card: Card): any
---@field public prohibit_use? fun(self: ProhibitSkill, player: Player, card: Card): any
---@field public prohibit_response? fun(self: ProhibitSkill, player: Player, card: Card): any
---@field public prohibit_discard? fun(self: ProhibitSkill, player: Player, card: Card): any
---@field public prohibit_pindian? fun(self: ProhibitSkill, from: Player, to: Player): any

---@param spec ProhibitSpec
---@return ProhibitSkill
function fk.CreateProhibitSkill(spec)
  local skel_name = spec.name
  -- 2. 构造骨骼

  local newspec={
    name = skel_name,
  }
  if spec.frequency then assert(type(spec.frequency) == "string") end

  local frequency = spec.frequency or Skill.NotFrequent
  newspec.tags={frequency}
  newspec.dynamicName = spec.dynamic_name
  newspec.dynamicDesc = spec.dynamic_desc
  local skeleton = fk.CreateSkill(newspec)
  --fk.readUsableSpecToSkill(skill, spec)
  fk.readCommonSpecToSkill(skeleton, spec)
  skeleton:addEffect("prohibit",spec)
  Fk.skill_skels[skeleton.name] = skel
  local skill = skeleton:createSkill()
  return skill
end

---@class AttackRangeSpec: StatusSkillSpec
---@field public correct_func? fun(self: AttackRangeSkill, from: Player, to: Player): number?
---@field public fixed_func? fun(self: AttackRangeSkill, player: Player): number?  @ 判定角色的锁定攻击范围初值
---@field public within_func? fun(self: AttackRangeSkill, from: Player, to: Player): any @ 判定to角色是否锁定在角色from攻击范围内
---@field public without_func? fun(self: AttackRangeSkill, from: Player, to: Player): any @ 判定to角色是否锁定在角色from攻击范围外

---@param spec AttackRangeSpec
---@return AttackRangeSkill
function fk.CreateAttackRangeSkill(spec)
  local skel_name = spec.name
  -- 2. 构造骨骼

  local newspec={
    name = skel_name,
  }
  if spec.frequency then assert(type(spec.frequency) == "string") end

  local frequency = spec.frequency or Skill.NotFrequent
  newspec.tags={frequency}
  newspec.dynamicName = spec.dynamic_name
  newspec.dynamicDesc = spec.dynamic_desc
  local skeleton = fk.CreateSkill(newspec)
  --fk.readUsableSpecToSkill(skill, spec)
  fk.readCommonSpecToSkill(skeleton, spec)
  skeleton:addEffect("atkrange",spec)
  local skill = skeleton:createSkill()
  Fk.skill_skels[skeleton.name] = skel
  return skill
end

---@class MaxCardsSpec: StatusSkillSpec
---@field public correct_func? fun(self: MaxCardsSkill, player: Player): number?
---@field public fixed_func? fun(self: MaxCardsSkill, player: Player): number?
---@field public exclude_from? fun(self: MaxCardsSkill, player: Player, card: Card): any

---@param spec MaxCardsSpec
---@return MaxCardsSkill
function fk.CreateMaxCardsSkill(spec)
  local skel_name = spec.name
  -- 2. 构造骨骼

  local newspec={
    name = skel_name,
  }
  if spec.frequency then assert(type(spec.frequency) == "string") end

  local frequency = spec.frequency or Skill.NotFrequent
  newspec.tags={frequency}
  newspec.dynamicName = spec.dynamic_name
  newspec.dynamicDesc = spec.dynamic_desc
  local skeleton = fk.CreateSkill(newspec)
  --fk.readUsableSpecToSkill(skill, spec)
  fk.readCommonSpecToSkill(skeleton, spec)
  skeleton:addEffect("maxcards",spec)
  local skill = skeleton:createSkill()
  Fk.skill_skels[skeleton.name] = skel
  return skill
end

---@class TargetModSpec: StatusSkillSpec
---@field public bypass_times? fun(self: TargetModSkill, player: Player, skill: ActiveSkill, scope: integer, card?: Card, to?: Player): any
---@field public residue_func? fun(self: TargetModSkill, player: Player, skill: ActiveSkill, scope: integer, card?: Card, to?: Player): number?
---@field public fix_times_func? fun(self: TargetModSkill, player: Player, skill: ActiveSkill, scope: integer, card?: Card, to?: Player): number?
---@field public bypass_distances? fun(self: TargetModSkill, player: Player, skill: ActiveSkill, card?: Card, to?: Player): any
---@field public distance_limit_func? fun(self: TargetModSkill, player: Player, skill: ActiveSkill, card?: Card, to?: Player): number?
---@field public extra_target_func? fun(self: TargetModSkill, player: Player, skill: ActiveSkill, card?: Card): number?
---@field public target_tip_func? fun(self: TargetModSkill, player: Player, to_select: integer, selected: integer[], selected_cards: integer[], card?: Card, selectable: boolean, extra_data: any): string|TargetTipDataSpec?

---@param spec TargetModSpec
---@return TargetModSkill
function fk.CreateTargetModSkill(spec)
  local skel_name = spec.name
  -- 2. 构造骨骼

  local newspec={
    name = skel_name,
  }
  if spec.frequency then assert(type(spec.frequency) == "string") end

  local frequency = spec.frequency or Skill.NotFrequent
  newspec.tags={frequency}
  newspec.dynamicName = spec.dynamic_name
  newspec.dynamicDesc = spec.dynamic_desc
  local skeleton = fk.CreateSkill(newspec)
  --fk.readUsableSpecToSkill(skill, spec)
  fk.readCommonSpecToSkill(skeleton, spec)
  skeleton:addEffect("targetmod",spec)
  local skill = skeleton:createSkill()
  Fk.skill_skels[skeleton.name] = skel
  return skill
end

---@class FilterSpec: StatusSkillSpec
---@field public card_filter? fun(self: FilterSkill, card: Card, player: Player, isJudgeEvent: boolean): any
---@field public view_as? fun(self: FilterSkill, card: Card, player: Player): Card?
---@field public equip_skill_filter? fun(self: FilterSkill, skill: Skill, player: Player): string?
---@field public handly_cards? fun(self: FilterSkill, player: Player): integer[]? @ 视为拥有可以如手牌般使用或打出的牌

---@param spec FilterSpec
---@return FilterSkill
function fk.CreateFilterSkill(spec)
  local skel_name = spec.name
  -- 2. 构造骨骼

  local newspec={
    name = skel_name,
  }
  if spec.frequency then assert(type(spec.frequency) == "string") end

  local frequency = spec.frequency or Skill.NotFrequent
  newspec.tags={frequency}
  newspec.dynamicName = spec.dynamic_name
  newspec.dynamicDesc = spec.dynamic_desc
  local skeleton = fk.CreateSkill(newspec)
  --fk.readUsableSpecToSkill(skill, spec)
  fk.readCommonSpecToSkill(skeleton, spec)
  skeleton:addEffect("filter",spec)
  local skill = skeleton:createSkill()
  Fk.skill_skels[skeleton.name] = skel
  return skill
end

---@class InvaliditySpec: StatusSkillSpec
---@field public invalidity_func? fun(self: InvaliditySkill, from: Player, skill: Skill): any @ 判定角色的技能是否无效
---@field public invalidity_attackrange? fun(self: InvaliditySkill, player: Player, card: Weapon): any @ 判定武器的攻击范围是否无效

---@param spec InvaliditySpec
---@return InvaliditySkill
function fk.CreateInvaliditySkill(spec)
  local skel_name = spec.name
  -- 2. 构造骨骼

  local newspec={
    name = skel_name,
  }
  if spec.frequency then assert(type(spec.frequency) == "string") end

  local frequency = spec.frequency or Skill.NotFrequent
  newspec.tags={frequency}
  newspec.dynamicName = spec.dynamic_name
  newspec.dynamicDesc = spec.dynamic_desc
  local skeleton = fk.CreateSkill(newspec)
  --fk.readUsableSpecToSkill(skill, spec)
  fk.readCommonSpecToSkill(skeleton, spec)
  skeleton:addEffect("invalidity",spec)
  local skill = skeleton:createSkill()
  Fk.skill_skels[skeleton.name] = skel
  return skill
end

---@class VisibilitySpec: StatusSkillSpec
---@field public card_visible? fun(self: VisibilitySkill, player: Player, card: Card): any
---@field public role_visible? fun(self: VisibilitySkill, player: Player, target: Player): any

---@param spec VisibilitySpec
function fk.CreateVisibilitySkill(spec)
  local skel_name = spec.name
  -- 2. 构造骨骼

  local newspec={
    name = skel_name,
  }
  if spec.frequency then assert(type(spec.frequency) == "string") end

  local frequency = spec.frequency or Skill.NotFrequent
  newspec.tags={frequency}
  newspec.dynamicName = spec.dynamic_name
  newspec.dynamicDesc = spec.dynamic_desc
  local skeleton = fk.CreateSkill(newspec)
  --fk.readUsableSpecToSkill(skill, spec)
  fk.readCommonSpecToSkill(skeleton, spec)
  skeleton:addEffect("visibility",spec)
  local skill = skeleton:createSkill()
  Fk.skill_skels[skeleton.name] = skel
  return skill
end

---@class CardSpec
---@field public name string @ 卡牌的名字
---@field public suit? Suit @ 卡牌的花色（四色及无花色）
---@field public number? integer @ 卡牌的点数（0到K）
---@field public skill? ActiveSkill
---@field public special_skills? string[]
---@field public is_damage_card? boolean
---@field public multiple_targets? boolean
---@field public is_passive? boolean


local function preprocessCardSpec(spec)
  assert(type(spec.name) == "string" or type(spec.class_name) == "string")
  if not spec.name then spec.name = spec.class_name
  elseif not spec.class_name then spec.class_name = spec.name end
  if spec.suit then assert(type(spec.suit) == "number") end
  if spec.number then assert(type(spec.number) == "number") end
end

local function readCardSpecToCard(card, spec)
  card.skill = spec.skill or (card.type == Card.TypeEquip and defaultEquipSkill or defaultCardSkill)
  card.skill.cardSkill = true
  card.special_skills = spec.special_skills
  card.is_damage_card = spec.is_damage_card
  card.multiple_targets = spec.multiple_targets
  card.is_passive = spec.is_passive
end



---@class EquipCardSpec: CardSpec
---@field public equip_skill? Skill
---@field public dynamic_equip_skills? fun(player: Player): Skill[]
---@field public on_install? fun(self: EquipCard, room: Room, player: ServerPlayer)
---@field public on_uninstall? fun(self: EquipCard, room: Room, player: ServerPlayer)

local function readCardSpecToEquip(card, spec)
  if spec.equip_skill then
    if spec.equip_skill.class and spec.equip_skill:isInstanceOf(Skill) then
      card.equip_skill = spec.equip_skill
      card.equip_skills = { spec.equip_skill }
    else
      card.equip_skill = spec.equip_skill[1]
      card.equip_skills = spec.equip_skill
    end
  end

  if spec.dynamic_equip_skills then
    assert(type(spec.dynamic_equip_skills) == "function")
    card.dynamicEquipSkills = spec.dynamic_equip_skills
  end

  if spec.on_install then card.onInstall = spec.on_install end
  if spec.on_uninstall then card.onUninstall = spec.on_uninstall end
end

---@class WeaponSpec: EquipCardSpec
---@field public attack_range? integer
---@field public dynamic_attack_range? fun(player: Player): integer

---@param spec WeaponSpec
---@return Weapon
function fk.CreateWeapon(spec)
  spec.type = Card.TypeEquip
  spec.sub_type = Card.SubtypeWeapon
  return fk.CreateCard(spec)
end

---@param spec EquipCardSpec
---@return Armor
function fk.CreateArmor(spec)
  spec.type = Card.TypeEquip
  spec.sub_type = Card.SubtypeArmor
  return fk.CreateCard(spec)
end

---@param spec EquipCardSpec
---@return DefensiveRide
function fk.CreateDefensiveRide(spec)
  spec.type = Card.TypeEquip
  spec.sub_type = Card.SubtypeDefensiveRide
  return fk.CreateCard(spec)
end

---@param spec EquipCardSpec
---@return OffensiveRide
function fk.CreateOffensiveRide(spec)
  spec.type = Card.TypeEquip
  spec.sub_type = Card.SubtypeOffensiveRide
  return fk.CreateCard(spec)
end

---@param spec EquipCardSpec
---@return Treasure
function fk.CreateTreasure(spec)
  spec.type = Card.TypeEquip
  spec.sub_type = Card.SubtypeTreasure
  return fk.CreateCard(spec)
end










--[[
for _, pkname in ipairs(Fk.package_names) do
    local pack = Fk.packages[pkname]

    for _, skel in ipairs(pack.card_skels) do
      local card = skel:createCardPrototype()
      if card then
        card.package = pack
        Fk.skills[card.skill.name] = Fk.skills[card.skill.name] or card.skill
        Fk.all_card_types[card.name] = card
        table.insert(Fk.all_card_names, card.name)
      end
    end
    for _, tab in ipairs(pack.card_specs) do
      pack:addCard(Fk:cloneCard(tab[1], tab[2], tab[3]))
    end

    -- add cards, generals and skills to Engine
    if pack.type == Package.CardPack then
      Fk:addCards(pack.cards)
    end
  end

--]]


  return extension